Get Data
We’ll load the raw data from all 8 .xls files. Each file shows the participant’s name, group, language, media, and x/y eye gaze coordinates. Here’s a quick glimpse of the data and how it’s structured after I’ve processed and cleaned it up.
# Import packages we'll need.
library(tidyverse)
library(stringr)
library(lme4)
library(lmerTest)
library(png)
library(grid)
# # Gather up the files
# files <- list.files(pattern = "\\.csv",path="../Adult Data/rawdata")
# files <- str_c("rawdata/",files)
# rawdata <- do.call("rbind", lapply(files, read_csv))
#
# # Clean Up
# rawdataoriginal <- rawdata
# rawdata <- rawdataoriginal
# rawdata <- rawdata %>%
# rename(participant = ParticipantName,
# group = "[Group]Value",
# language = "[Language]Value",
# media = MediaName,
# x = "GazePointX (MCSpx)",
# y = "GazePointY (MCSpx)",
# gazeindex = GazePointIndex) %>%
# select(participant,group,language,media,x,y,gazeindex) %>%
# add_column(story=NA,direction=NA,maingroup=NA) %>%
# mutate(story = case_when(
# str_detect(media,"bears") ~ "bears",
# str_detect(media,"cinderella") ~ "cinderella",
# str_detect(media,"midas") ~ "midas",
# str_detect(media,"redridinghood") ~ "redridinghood")) %>%
# mutate(direction = case_when(
# str_detect(media,"FW") ~ "forward",
# str_detect(media,"ER") ~ "reversed")) %>%
# mutate(media = str_c(story,direction, sep="_")) %>%
# mutate(language = case_when(
# str_detect(language,"EarlyASL") ~ "Early",
# str_detect(language,"LateASL") ~ "Late",
# str_detect(language,"NoviceASL_Trained") ~ "Trained",
# str_detect(language,"NoviceASL") ~ "Novice")) %>%
# mutate(maingroup = str_c(group,language, sep="")) %>%
# filter(!is.na(maingroup))
# glimpse(rawdata)
Now that it’s in the right format…it’s easy to get what we need! :-D
Analysis
First, let’s trim each participant’s data, getting rid of the first 30 samples (0.5 secs). Then we’ll get the the mean x and y coordinate for each story for each participant.
#write_csv(rawdata,"adultviewingspaceraw.csv")
rawdata <- read_csv("../Adult Data/rawdata/adultviewingspaceraw.csv")
Parsed with column specification:
cols(
participant = col_character(),
group = col_character(),
language = col_character(),
media = col_character(),
x = col_integer(),
y = col_integer(),
gazeindex = col_integer(),
story = col_character(),
direction = col_character(),
maingroup = col_character()
)
rawdata <- rawdata %>%
arrange(participant,media,gazeindex) %>%
group_by(participant,media) %>%
slice(30:n())
means <- rawdata %>%
group_by(participant,media) %>%
summarise(x = mean(x,na.rm=TRUE),
y = mean(y,na.rm=TRUE))
head(means,10)
And I can get x or y plots of one participant across 4 stories. Let’s do Adam (me?). We’ll set the x and y limits to the whole width of the Tobii monitor (1600x1200). But because Tobii considers (0,0) to be the upper left corner (and not the bottom left corner), we also need to flip the y axis.
adam <- filter(rawdata,participant=="Adam") %>% mutate(y = y*-1)
ggplot(adam,aes(x=x,y=y,color=media)) + geom_point(size=0.1) + geom_path() + facet_wrap("media",ncol=2,nrow=2) + guides(color="none") + scale_x_continuous(limit=c(0,1600)) + scale_y_continuous(limit=c(-1200,0))

Cool, yeah?
Let’s try this again but let the x and y limits match the data. That will “zoom” in. We’ll also get rid of that weird right-side outlier in RRH. Neatooooo.
adam <- filter(adam,x<800)
ggplot(adam,aes(x=x,y=y,color=media)) + geom_point(size=0.1) + geom_path() + facet_wrap("media",ncol=2,nrow=2) + guides(color="none")

IQR
Now let’s get the middle 50% (aka the IQR) of x and y for each participant’s story (we’ve already trimmed the first 30 samples). That should also take care of further weird outliers. And we are defining “viewing space” as the IQR of the x and y axis.
iqr <- rawdata %>%
group_by(participant,media) %>%
dplyr::summarize(xIQR = IQR(x,na.rm=TRUE),
yIQR = IQR(y,na.rm=TRUE),
xmed = median(x, na.rm=TRUE),
ymed = median(y, na.rm=TRUE))
head(iqr,10)
And check out the histograms:
iqr %>%
gather(axis,iqr,xIQR:yIQR) %>%
ggplot(aes(x=iqr,fill=axis)) + geom_histogram() + facet_grid(axis~.)

There’s one weird outlier for xIQR. That’s Rebecca. Let’s look at her data.
rebecca <- filter(rawdata,participant=="Rebecca") %>% mutate(y = y*-1)
ggplot(rebecca,aes(x=x,y=y,color=media)) + geom_point(size=0.1) + geom_path() + facet_wrap("media",ncol=2,nrow=2) + guides(color="none") + xlim(0,1440) + ylim(-1080,0)

So we’ll remove Rebecca’s midas_forward story. Next, check the medians.
iqr %>%
gather(axis,med,xmed:ymed) %>%
ggplot(aes(x=med,fill=axis)) + geom_histogram() + facet_grid(axis~.)

Looks great! But it also looks pretty interesting doesn’t it…Y median has a wider spread than X median. That would make sense.
Now we’re ready to do stats based on group, direction, etc.
rbc <- tribble(~participant, ~media, "Rebecca","midas_forward")
iqr <- iqr %>%
ungroup() %>%
anti_join(rbc, by=c("participant","media")) # for some reason filter wouldn't work
subjectinfo <- rawdata %>%
select(participant,maingroup,group,language,media,story,direction) %>%
distinct() %>%
filter(!is.na(participant))
iqr <- iqr %>%
left_join(subjectinfo,by=c("participant","media")) %>%
filter(!is.na(maingroup))
iqr.gather <- iqr %>% gather(axis,value,xIQR:ymed)
iqr.iqr <- filter(iqr.gather,axis=="xIQR" | axis=="yIQR")
iqr.med <- filter(iqr.gather,axis=="xmed" | axis=="ymed")
ggplot(iqr.iqr,aes(x=maingroup,y=value,fill=direction)) +
geom_boxplot() + theme(axis.text.x=element_text(angle=45,hjust=1)) +
facet_grid(.~axis)

And the median x and y position (this assumes all calibrations are correct):
ggplot(iqr.med,aes(x=maingroup,y=value,fill=direction)) +
geom_boxplot() + theme(axis.text.x=element_text(angle=45,hjust=1)) +
facet_grid(.~axis)

First, does reversal have an effect on X IQR? We have random intercepts for each participant and media, and a random slope adjustment for reversed for each participant.
xiqr.reversal <- lmer(xIQR ~ direction + (direction|participant) + (1|media), data = iqr)
summary(xiqr.reversal)$coefficients
Estimate Std. Error df t value Pr(>|t|)
(Intercept) 37.067311 4.297525 5.879626 8.6252701 0.0001491978
directionreversed 2.396059 5.922401 5.288700 0.4045755 0.7016363535
Welp. No. Y IQR?
yiqr.reversal <- lmer(yIQR ~ direction + (direction|participant) + (1|media), data = iqr)
summary(yiqr.reversal)$coefficients
Estimate Std. Error df t value Pr(>|t|)
(Intercept) 46.043362 4.200520 6.970763 10.9613480 1.200581e-05
directionreversed 4.845994 5.370947 4.578010 0.9022605 4.118721e-01
No effect here either. Let’s try adding maingroups. X IQR first.
xiqr.group <- lmer(xIQR ~ direction * maingroup + (direction|participant) + (1|media), data = iqr)
summary(xiqr.group)$coefficients
Estimate Std. Error df t value Pr(>|t|)
(Intercept) 34.6927610 4.977661 9.371920 6.96969146 5.346237e-05
directionreversed 6.1771409 6.649067 7.438029 0.92902372 3.820371e-01
maingroupDeafLate -3.1765664 4.967385 78.798842 -0.63948467 5.243625e-01
maingroupHearingEarly -0.4499422 7.743459 73.051139 -0.05810609 9.538228e-01
maingroupHearingLate 7.1504388 4.359923 75.858667 1.64003778 1.051379e-01
maingroupHearingNovice 1.7218180 4.676980 74.285758 0.36814740 7.138103e-01
maingroupHearingTrained 6.1822390 4.333229 74.566382 1.42670499 1.578388e-01
directionreversed:maingroupDeafLate -5.3237257 5.606349 109.885316 -0.94958867 3.444051e-01
directionreversed:maingroupHearingEarly -5.7646039 8.485478 106.947583 -0.67934934 4.983842e-01
directionreversed:maingroupHearingLate -7.9499453 4.850258 110.002650 -1.63907694 1.040542e-01
directionreversed:maingroupHearingNovice -4.5441561 5.174925 107.927462 -0.87811047 3.818344e-01
directionreversed:maingroupHearingTrained -2.8665334 4.835685 109.082262 -0.59278748 5.545503e-01
This means there is a significant difference of DeafEarly vs. HearingLate and HearingTrained on xIQR, but in the forward condition only. Basically, those two groups have a “wider” viewing space than other groups.
yiqr.group <- lmer(yIQR ~ direction * maingroup + (direction|participant) + (1|media), data = iqr)
summary(yiqr.group)$coefficients
Estimate Std. Error df t value Pr(>|t|)
(Intercept) 43.6712994 5.694180 22.801965 7.66946239 9.299788e-08
directionreversed 2.2511171 6.477516 9.643778 0.34752785 7.356598e-01
maingroupDeafLate 0.5128043 8.350353 72.818563 0.06141110 9.512001e-01
maingroupHearingEarly -4.5089659 13.105397 67.201619 -0.34405412 7.318798e-01
maingroupHearingLate 0.6217192 7.364000 69.503009 0.08442684 9.329598e-01
maingroupHearingNovice 4.4728826 7.906578 68.286947 0.56571661 5.734407e-01
maingroupHearingTrained 8.7840578 7.325681 68.444490 1.19907732 2.346327e-01
directionreversed:maingroupDeafLate -6.0754371 8.026624 142.796568 -0.75691059 4.503505e-01
directionreversed:maingroupHearingEarly 1.0060946 12.144589 140.217132 0.08284304 9.340945e-01
directionreversed:maingroupHearingLate 4.4331711 6.951655 142.667852 0.63771449 5.246817e-01
directionreversed:maingroupHearingNovice 8.5502379 7.409162 140.930045 1.15400881 2.504498e-01
directionreversed:maingroupHearingTrained 5.8176819 6.927937 141.706193 0.83974235 4.024674e-01
No differences among groups or reversal effect for xIQR. Viewing space doesn’t get significantly taller or shorter.
Viewing Space Charts
I want to learn how to make rectangle plots so here we go. Using each participant’s four x and y medians and 4 x and y IQRs (one set for each story, for 4 stories). So I can get the logic and code down. Let’s assume all calibrations were correct. Here’s the chart for the whole media size of 1440x1080 (as reported in Tobii).
# In this order, we'll get a grand median by taking a participant's median across their 4 stories, than the median for forward and reverse across all participants.
medians <- iqr %>%
group_by(maingroup, participant,direction) %>%
dplyr::summarize(xIQR = median(xIQR,na.rm=TRUE),
yIQR = median(yIQR,na.rm=TRUE),
xmed = median(xmed,na.rm=TRUE),
ymed = median(ymed,na.rm=TRUE)) %>%
group_by(maingroup, direction) %>%
dplyr::summarize(xIQR = median(xIQR,na.rm=TRUE),
yIQR = median(yIQR,na.rm=TRUE),
x = median(xmed,na.rm=TRUE),
y = median(ymed,na.rm=TRUE))
medians <- medians %>%
mutate(y = y*-1,
xmin = x-(xIQR/2),
xmax = x+(xIQR/2),
ymin = y-(yIQR/2),
ymax = y+(yIQR/2))
img <- readPNG("cindy.png")
g <- rasterGrob(img, interpolate=TRUE, width=unit(1,"npc"), height=unit(1,"npc"))
ggplot(medians, aes(fill=direction,color=direction)) +
annotation_custom(g, xmin=-Inf, xmax=Inf, ymin=-Inf, ymax=Inf) +
geom_rect(aes(xmin=xmin,ymin=ymin,xmax=xmax,ymax=ymax),alpha=.1) +
theme_linedraw() +
scale_x_continuous(limits = c(0,1440), expand = c(0, 0)) +
scale_y_continuous(limits = c(-1080,0), expand = c(0, 0)) +
facet_wrap("maingroup")

# ggplot(iqr.global, aes(fill=direction,color=direction)) +
# annotation_custom(g, xmin=-Inf, xmax=Inf, ymin=-Inf, ymax=Inf) +
# geom_rect(aes(xmin=xmin,ymin=ymin,xmax=xmax,ymax=ymax),alpha=.1) +
# theme_minimal() + xlim(0,1440) + ylim(-1080,0) +
# geom_hline(yintercept=-1080+885) +
# geom_hline(yintercept=-1080+525) +
# annotate(geom="text", x = 300, y = -1080+555, label = "upper shoulder point") +
# annotate(geom="point", x = 535, y = -1080+525) +
# annotate(geom="text", x = 535, y = -1080+910, label = "height line") +
# annotate(geom="rect", xmin = 535, xmax = 535+365, ymin = -525-551, ymax = -1080+525, fill="maroon", color="black", alpha=0.5) +
# annotate(geom="text", x = 700, y = -900, label = "torso")
Yayyy! It worked! A bit hard to see! Let’s zoom in.
# ggplot(iqr.global, aes(fill=direction,color=direction)) +
# annotation_custom(g, xmin=0, xmax=1440, ymin=-1080, ymax=0) +
# geom_rect(aes(xmin=xmin,ymin=ymin,xmax=xmax,ymax=ymax),alpha=.1) +
# theme_minimal() + xlim(600,800) + ylim(-500,-300)
ggplot(medians, aes(fill=direction,color=direction)) +
geom_rect(aes(xmin=xmin,ymin=ymin,xmax=xmax,ymax=ymax),alpha=.1) +
theme_minimal() + xlim(677,743) + ylim(-421,-370)

#ggplot(iqr.global, aes(fill=direction,color=direction)) +
# geom_rect(aes(xmin=xmin,ymin=ymin,xmax=xmax,ymax=ymax),alpha=.1)
I have to figure out how to get Cindy to zoom in - or crop a zoomed in version of Cindy manually and use that.
Standard Deviations?
Let’s try using standard deviations instead.
sd <- rawdata %>%
group_by(participant,media) %>%
dplyr::summarize(xsd = sd(x,na.rm=TRUE),
ysd = sd(y,na.rm=TRUE),
xmean = mean(x, na.rm=TRUE),
ymean = mean(y, na.rm=TRUE))
sd.individuals <- sd %>%
rename(x = xmean,
y = ymean) %>%
mutate(y = y*-1,
xmin = x-xsd,
xmax = x+xsd,
ymin = y-ysd,
ymax = y+ysd) %>%
left_join(subjectinfo,by=c("participant","media")) %>%
filter(!is.na(maingroup))
ggplot(sd.individuals, aes(fill=direction,color=direction)) +
annotation_custom(g, xmin=-Inf, xmax=Inf, ymin=-Inf, ymax=Inf) +
geom_rect(aes(xmin=xmin,ymin=ymin,xmax=xmax,ymax=ymax),alpha=.1) +
theme_minimal() + xlim(0,1440) + ylim(-1080,0) + facet_wrap("direction") +
ggtitle("with SDs")

Now let’s make Outer Limits charts which is IQR +/- 2 SDs.
sd.individuals <- select(sd.individuals,participant,media,xsd,ysd)
iqrsd.individuals <- left_join(iqr.individuals,sd.individuals,by=c("participant","media")) %>%
mutate(xmin = xmin-(2*xsd),
xmax = xmax+(2*xsd),
ymin = ymin-(2*ysd),
ymax = ymax+(2*ysd))
ggplot(iqrsd.individuals, aes(fill=direction,color=direction)) +
annotation_custom(g, xmin=-Inf, xmax=Inf, ymin=-Inf, ymax=Inf) +
geom_rect(aes(xmin=xmin,ymin=ymin,xmax=xmax,ymax=ymax),alpha=.1) +
theme_minimal() + xlim(0,1440) + ylim(-1080,0) + facet_wrap("direction") +
ggtitle("with SDs")

iqrsd.individuals <- iqrsd.individuals %>%
group_by(direction) %>%
dplyr::summarize(x = mean(x,na.rm=TRUE),
y = mean(y,na.rm=TRUE),
xmin = mean(xmin,na.rm=TRUE),
ymin = mean(ymin,na.rm=TRUE),
xmax = mean(xmax,na.rm=TRUE),
ymax = mean(ymax,na.rm=TRUE))
ggplot(iqrsd.individuals, aes(fill=direction,color=direction)) +
annotation_custom(g, xmin=-Inf, xmax=Inf, ymin=-Inf, ymax=Inf) +
geom_rect(aes(xmin=xmin,ymin=ymin,xmax=xmax,ymax=ymax),alpha=.1) +
theme_minimal() + xlim(0,1440) + ylim(-1080,0) + facet_wrap("direction") +
ggtitle("Average of above chart (rain's outer limits)")

XY Space Data - Multiple Plots
First let’s prep the data.
multiples <- rawdata %>%
filter(!is.na(x)) %>%
filter(!is.na(y)) %>%
rename(lang = maingroup,
name = participant) %>%
group_by(name, lang, direction, story) %>%
summarise(xIQR = IQR(x,na.rm=TRUE),
yIQR = IQR(y,na.rm=TRUE),
xmed = median(x, na.rm=TRUE),
ymed = median(y, na.rm=TRUE),
area = xIQR*yIQR,
x_90 = quantile(x, .95, na.rm=TRUE) - quantile(x, .05, na.rm=TRUE),
y_90 = quantile(y, .95, na.rm=TRUE) - quantile(y, .05, na.rm=TRUE),
area_90 = (x_90) * (y_90),
x_mean = mean(x, na.rm = TRUE),
y_mean = mean(y, na.rm = TRUE),
x_sd = sd(x, na.rm = TRUE),
y_sd = sd(y, na.rm = TRUE),
x_1sd = (x_mean+x_sd) - (x_mean-x_sd),
y_1sd = (y_mean+y_sd) - (y_mean-y_sd),
area_1sd = x_1sd * y_1sd,
x_2sd = (x_mean+(x_sd*2)) - (x_mean-(x_sd*2)),
y_2sd = (y_mean+(y_sd*2)) - (y_mean-(y_sd*2)),
area_2sd = x_2sd * y_2sd) %>%
group_by(name, lang, direction) %>%
summarise_if(is.double, funs(mean), na.rm = T) %>%
group_by(lang, direction) %>%
summarise_if(is.double, funs(mean), na.rm = T) %>%
filter(lang == "DeafEarly" || lang == "HearingNovice")
img <- png::readPNG("cindy.png")
g <- grid::rasterGrob(img, interpolate=TRUE, width=unit(1,"npc"), height=unit(1,"npc"))
IQR (Middle 50%)
Let’s see.
curr_data <- multiples %>%
ungroup() %>%
select(lang, direction, xmed, ymed, xIQR, yIQR) %>%
group_by(lang, direction) %>%
summarise(xmin = xmed-(xIQR/2),
xmax = xmed+(xIQR/2),
ymin = -1*(ymed-(yIQR/2)),
ymax = -1*(ymed+(yIQR/2)))
ggplot(curr_data, aes(fill=direction,color=direction)) +
annotation_custom(g, xmin=-Inf, xmax=Inf, ymin=-Inf, ymax=Inf) +
geom_rect(aes(xmin=xmin,ymin=ymin,xmax=xmax,ymax=ymax),alpha=.1) +
theme_linedraw() +
scale_x_continuous(limits = c(0,1440), expand = c(0, 0)) +
scale_y_continuous(limits = c(-1080,0), expand = c(0, 0)) +
facet_wrap("lang")

Middle 90%
So I calculated the average median across, and the middle 90% of the data.
curr_data <- multiples %>%
ungroup() %>%
select(lang, direction, xmed, ymed, x_90, y_90) %>%
group_by(lang, direction) %>%
summarise(xmin = xmed-(x_90/2),
xmax = xmed+(x_90/2),
ymin = -1*(ymed-(y_90/2)),
ymax = -1*(ymed+(y_90/2)))
ggplot(curr_data, aes(fill=direction,color=direction)) +
annotation_custom(g, xmin=-Inf, xmax=Inf, ymin=-Inf, ymax=Inf) +
geom_rect(aes(xmin=xmin,ymin=ymin,xmax=xmax,ymax=ymax),alpha=.1) +
theme_linedraw() +
scale_x_continuous(limits = c(0,1440), expand = c(0, 0)) +
scale_y_continuous(limits = c(-1080,0), expand = c(0, 0)) +
facet_wrap("lang")

±1 SD (Middle 68%)
So this is using the mean of the means, plus or minus one SD. This is equivalent to middle 68%.
curr_data <- multiples %>%
ungroup() %>%
select(lang, direction, x_mean, y_mean, x_1sd, y_1sd) %>%
group_by(lang, direction) %>%
summarise(xmin = x_mean-(x_1sd/2),
xmax = x_mean+(x_1sd/2),
ymin = -1*(y_mean-(y_1sd/2)),
ymax = -1*(y_mean+(y_1sd/2)))
ggplot(curr_data, aes(fill=direction,color=direction)) +
annotation_custom(g, xmin=-Inf, xmax=Inf, ymin=-Inf, ymax=Inf) +
geom_rect(aes(xmin=xmin,ymin=ymin,xmax=xmax,ymax=ymax),alpha=.1) +
theme_linedraw() +
scale_x_continuous(limits = c(0,1440), expand = c(0, 0)) +
scale_y_continuous(limits = c(-1080,0), expand = c(0, 0)) +
facet_wrap("lang")

±2 SD (Middle 96%)
And this is using the mean of the means, plus or minus two SD. This is equivalent to middle 96%.
curr_data <- multiples %>%
ungroup() %>%
select(lang, direction, x_mean, y_mean, x_2sd, y_2sd) %>%
group_by(lang, direction) %>%
summarise(xmin = x_mean-(x_2sd/2),
xmax = x_mean+(x_2sd/2),
ymin = -1*(y_mean-(y_2sd/2)),
ymax = -1*(y_mean+(y_2sd/2)))
ggplot(curr_data, aes(fill=direction,color=direction)) +
annotation_custom(g, xmin=-Inf, xmax=Inf, ymin=-Inf, ymax=Inf) +
geom_rect(aes(xmin=xmin,ymin=ymin,xmax=xmax,ymax=ymax),alpha=.1) +
theme_linedraw() +
scale_x_continuous(limits = c(0,1440), expand = c(0, 0)) +
scale_y_continuous(limits = c(-1080,0), expand = c(0, 0)) +
facet_wrap("lang")

LS0tCnRpdGxlOiAiVmlld2luZyBTcGFjZSAoc3R1ZHkxYWR1bHRzKSIKYXV0aG9yOiAiQWRhbSBTdG9uZSwgUGhEIiAKZGF0ZTogJ2ByIGZvcm1hdChTeXMuRGF0ZSgpLCAiJW0tJWQtJVkiKWAnCm91dHB1dDoKICBnaXRodWJfZG9jdW1lbnQ6CiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiAyCiAgaHRtbF9ub3RlYm9vazoKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgdGhlbWU6IHBhcGVyCiAgICBoaWdobGlnaHQ6IHRhbmdvCiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiAyCiAgICB0b2NfZmxvYXQ6IHllcwogICAgZGZfcHJpbnQ6IHBhZ2VkCi0tLQoKIyBHZXQgRGF0YQpXZSdsbCBsb2FkIHRoZSByYXcgZGF0YSBmcm9tIGFsbCA4IC54bHMgZmlsZXMuIEVhY2ggZmlsZSBzaG93cyB0aGUgcGFydGljaXBhbnQncyBuYW1lLCBncm91cCwgbGFuZ3VhZ2UsIG1lZGlhLCBhbmQgeC95IGV5ZSBnYXplIGNvb3JkaW5hdGVzLiBIZXJlJ3MgYSBxdWljayBnbGltcHNlIG9mIHRoZSBkYXRhIGFuZCBob3cgaXQncyBzdHJ1Y3R1cmVkIGFmdGVyIEkndmUgcHJvY2Vzc2VkIGFuZCBjbGVhbmVkIGl0IHVwLiAKYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMgSW1wb3J0IHBhY2thZ2VzIHdlJ2xsIG5lZWQuCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHN0cmluZ3IpCmxpYnJhcnkobG1lNCkKbGlicmFyeShsbWVyVGVzdCkKbGlicmFyeShwbmcpCmxpYnJhcnkoZ3JpZCkKCiMgIyBHYXRoZXIgdXAgdGhlIGZpbGVzCiMgZmlsZXMgPC0gbGlzdC5maWxlcyhwYXR0ZXJuID0gIlxcLmNzdiIscGF0aD0iLi4vQWR1bHQgRGF0YS9yYXdkYXRhIikKIyBmaWxlcyA8LSBzdHJfYygicmF3ZGF0YS8iLGZpbGVzKQojIHJhd2RhdGEgPC0gZG8uY2FsbCgicmJpbmQiLCBsYXBwbHkoZmlsZXMsIHJlYWRfY3N2KSkKIyAKIyAjIENsZWFuIFVwCiMgcmF3ZGF0YW9yaWdpbmFsIDwtIHJhd2RhdGEKIyByYXdkYXRhIDwtIHJhd2RhdGFvcmlnaW5hbAojIHJhd2RhdGEgPC0gcmF3ZGF0YSAlPiUKIyAgIHJlbmFtZShwYXJ0aWNpcGFudCA9IFBhcnRpY2lwYW50TmFtZSwKIyAgICAgICAgICBncm91cCA9ICJbR3JvdXBdVmFsdWUiLAojICAgICAgICAgIGxhbmd1YWdlID0gIltMYW5ndWFnZV1WYWx1ZSIsCiMgICAgICAgICAgbWVkaWEgPSBNZWRpYU5hbWUsCiMgICAgICAgICAgeCA9ICJHYXplUG9pbnRYIChNQ1NweCkiLAojICAgICAgICAgIHkgPSAiR2F6ZVBvaW50WSAoTUNTcHgpIiwKIyAgICAgICAgICBnYXplaW5kZXggPSBHYXplUG9pbnRJbmRleCkgJT4lCiMgICBzZWxlY3QocGFydGljaXBhbnQsZ3JvdXAsbGFuZ3VhZ2UsbWVkaWEseCx5LGdhemVpbmRleCkgJT4lCiMgICBhZGRfY29sdW1uKHN0b3J5PU5BLGRpcmVjdGlvbj1OQSxtYWluZ3JvdXA9TkEpICU+JQojICAgbXV0YXRlKHN0b3J5ID0gY2FzZV93aGVuKAojICAgICBzdHJfZGV0ZWN0KG1lZGlhLCJiZWFycyIpIH4gImJlYXJzIiwKIyAgICAgc3RyX2RldGVjdChtZWRpYSwiY2luZGVyZWxsYSIpIH4gImNpbmRlcmVsbGEiLCAgIAojICAgICBzdHJfZGV0ZWN0KG1lZGlhLCJtaWRhcyIpIH4gIm1pZGFzIiwKIyAgICAgc3RyX2RldGVjdChtZWRpYSwicmVkcmlkaW5naG9vZCIpIH4gInJlZHJpZGluZ2hvb2QiKSkgJT4lCiMgICBtdXRhdGUoZGlyZWN0aW9uID0gY2FzZV93aGVuKAojICAgICBzdHJfZGV0ZWN0KG1lZGlhLCJGVyIpIH4gImZvcndhcmQiLAojICAgICBzdHJfZGV0ZWN0KG1lZGlhLCJFUiIpIH4gInJldmVyc2VkIikpICU+JQojICAgbXV0YXRlKG1lZGlhID0gc3RyX2Moc3RvcnksZGlyZWN0aW9uLCBzZXA9Il8iKSkgJT4lCiMgICBtdXRhdGUobGFuZ3VhZ2UgPSBjYXNlX3doZW4oCiMgICAgIHN0cl9kZXRlY3QobGFuZ3VhZ2UsIkVhcmx5QVNMIikgfiAiRWFybHkiLAojICAgICBzdHJfZGV0ZWN0KGxhbmd1YWdlLCJMYXRlQVNMIikgfiAiTGF0ZSIsCiMgICAgIHN0cl9kZXRlY3QobGFuZ3VhZ2UsIk5vdmljZUFTTF9UcmFpbmVkIikgfiAiVHJhaW5lZCIsCiMgICAgIHN0cl9kZXRlY3QobGFuZ3VhZ2UsIk5vdmljZUFTTCIpIH4gIk5vdmljZSIpKSAlPiUKIyAgIG11dGF0ZShtYWluZ3JvdXAgPSBzdHJfYyhncm91cCxsYW5ndWFnZSwgc2VwPSIiKSkgJT4lCiMgICBmaWx0ZXIoIWlzLm5hKG1haW5ncm91cCkpCiMgZ2xpbXBzZShyYXdkYXRhKQpgYGAKCk5vdyB0aGF0IGl0J3MgaW4gdGhlIHJpZ2h0IGZvcm1hdC4uLml0J3MgZWFzeSB0byBnZXQgd2hhdCB3ZSBuZWVkISA6LUQgCgojIEFuYWx5c2lzCgpGaXJzdCwgbGV0J3MgdHJpbSBlYWNoIHBhcnRpY2lwYW50J3MgZGF0YSwgZ2V0dGluZyByaWQgb2YgdGhlIGZpcnN0IDMwIHNhbXBsZXMgKDAuNSBzZWNzKS4gVGhlbiB3ZSdsbCBnZXQgdGhlIHRoZSBtZWFuIHggYW5kIHkgY29vcmRpbmF0ZSBmb3IgZWFjaCBzdG9yeSBmb3IgZWFjaCBwYXJ0aWNpcGFudC4KCmBgYHtyfQoKI3dyaXRlX2NzdihyYXdkYXRhLCJhZHVsdHZpZXdpbmdzcGFjZXJhdy5jc3YiKQpyYXdkYXRhIDwtIHJlYWRfY3N2KCIuLi9BZHVsdCBEYXRhL3Jhd2RhdGEvYWR1bHR2aWV3aW5nc3BhY2VyYXcuY3N2IikKCnJhd2RhdGEgPC0gcmF3ZGF0YSAlPiUKICBhcnJhbmdlKHBhcnRpY2lwYW50LG1lZGlhLGdhemVpbmRleCkgJT4lCiAgZ3JvdXBfYnkocGFydGljaXBhbnQsbWVkaWEpICU+JQogIHNsaWNlKDMwOm4oKSkKCm1lYW5zIDwtIHJhd2RhdGEgJT4lCiAgZ3JvdXBfYnkocGFydGljaXBhbnQsbWVkaWEpICU+JQogIHN1bW1hcmlzZSh4ID0gbWVhbih4LG5hLnJtPVRSVUUpLAogICAgICAgICAgICB5ID0gbWVhbih5LG5hLnJtPVRSVUUpKQpoZWFkKG1lYW5zLDEwKQpgYGAKCkFuZCBJIGNhbiBnZXQgeCBvciB5IHBsb3RzIG9mIG9uZSBwYXJ0aWNpcGFudCBhY3Jvc3MgNCBzdG9yaWVzLiBMZXQncyBkbyBBZGFtIChtZT8pLiBXZSdsbCBzZXQgdGhlIHggYW5kIHkgbGltaXRzIHRvIHRoZSB3aG9sZSB3aWR0aCBvZiB0aGUgVG9iaWkgbW9uaXRvciAoMTYwMHgxMjAwKS4gQnV0IGJlY2F1c2UgVG9iaWkgY29uc2lkZXJzICgwLDApIHRvIGJlIHRoZSB1cHBlciBsZWZ0IGNvcm5lciAoYW5kIG5vdCB0aGUgYm90dG9tIGxlZnQgY29ybmVyKSwgd2UgYWxzbyBuZWVkIHRvIGZsaXAgdGhlIHkgYXhpcy4gCgpgYGB7cn0KYWRhbSA8LSBmaWx0ZXIocmF3ZGF0YSxwYXJ0aWNpcGFudD09IkFkYW0iKSAlPiUgbXV0YXRlKHkgPSB5Ki0xKQpnZ3Bsb3QoYWRhbSxhZXMoeD14LHk9eSxjb2xvcj1tZWRpYSkpICsgZ2VvbV9wb2ludChzaXplPTAuMSkgKyBnZW9tX3BhdGgoKSArIGZhY2V0X3dyYXAoIm1lZGlhIixuY29sPTIsbnJvdz0yKSArIGd1aWRlcyhjb2xvcj0ibm9uZSIpICsgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0PWMoMCwxNjAwKSkgKyBzY2FsZV95X2NvbnRpbnVvdXMobGltaXQ9YygtMTIwMCwwKSkKYGBgCkNvb2wsIHllYWg/IAoKTGV0J3MgdHJ5IHRoaXMgYWdhaW4gYnV0IGxldCB0aGUgeCBhbmQgeSBsaW1pdHMgbWF0Y2ggdGhlIGRhdGEuIFRoYXQgd2lsbCAiem9vbSIgaW4uIFdlJ2xsIGFsc28gZ2V0IHJpZCBvZiB0aGF0IHdlaXJkIHJpZ2h0LXNpZGUgb3V0bGllciBpbiBSUkguICBOZWF0b29vb28uIAoKYGBge3J9CmFkYW0gPC0gZmlsdGVyKGFkYW0seDw4MDApCmdncGxvdChhZGFtLGFlcyh4PXgseT15LGNvbG9yPW1lZGlhKSkgKyBnZW9tX3BvaW50KHNpemU9MC4xKSArIGdlb21fcGF0aCgpICsgZmFjZXRfd3JhcCgibWVkaWEiLG5jb2w9Mixucm93PTIpICsgZ3VpZGVzKGNvbG9yPSJub25lIikgCmBgYAoKIyBJUVIgCk5vdyBsZXQncyBnZXQgdGhlIG1pZGRsZSA1MCUgKGFrYSB0aGUgSVFSKSBvZiB4IGFuZCB5IGZvciBlYWNoIHBhcnRpY2lwYW50J3Mgc3RvcnkgKHdlJ3ZlIGFscmVhZHkgdHJpbW1lZCB0aGUgZmlyc3QgMzAgc2FtcGxlcykuIFRoYXQgc2hvdWxkIGFsc28gdGFrZSBjYXJlIG9mIGZ1cnRoZXIgd2VpcmQgb3V0bGllcnMuIEFuZCB3ZSBhcmUgZGVmaW5pbmcgInZpZXdpbmcgc3BhY2UiIGFzIHRoZSBJUVIgb2YgdGhlIHggYW5kIHkgYXhpcy4gCgpgYGB7cn0KaXFyIDwtIHJhd2RhdGEgJT4lCiAgZ3JvdXBfYnkocGFydGljaXBhbnQsbWVkaWEpICU+JQogIGRwbHlyOjpzdW1tYXJpemUoeElRUiA9IElRUih4LG5hLnJtPVRSVUUpLAogICAgICAgICAgICAgICAgICAgeUlRUiA9IElRUih5LG5hLnJtPVRSVUUpLAogICAgICAgICAgICAgICAgICAgeG1lZCA9IG1lZGlhbih4LCBuYS5ybT1UUlVFKSwKICAgICAgICAgICAgICAgICAgIHltZWQgPSBtZWRpYW4oeSwgbmEucm09VFJVRSkpCmhlYWQoaXFyLDEwKQpgYGAKCkFuZCBjaGVjayBvdXQgdGhlIGhpc3RvZ3JhbXM6CgpgYGB7cn0KaXFyICU+JSAKICBnYXRoZXIoYXhpcyxpcXIseElRUjp5SVFSKSAlPiUKICBnZ3Bsb3QoYWVzKHg9aXFyLGZpbGw9YXhpcykpICsgZ2VvbV9oaXN0b2dyYW0oKSArIGZhY2V0X2dyaWQoYXhpc34uKQpgYGAKClRoZXJlJ3Mgb25lIHdlaXJkIG91dGxpZXIgZm9yIHhJUVIuIFRoYXQncyBSZWJlY2NhLiBMZXQncyBsb29rIGF0IGhlciBkYXRhLiAKCmBgYHtyfQpyZWJlY2NhIDwtIGZpbHRlcihyYXdkYXRhLHBhcnRpY2lwYW50PT0iUmViZWNjYSIpICU+JSBtdXRhdGUoeSA9IHkqLTEpCmdncGxvdChyZWJlY2NhLGFlcyh4PXgseT15LGNvbG9yPW1lZGlhKSkgKyBnZW9tX3BvaW50KHNpemU9MC4xKSArIGdlb21fcGF0aCgpICsgZmFjZXRfd3JhcCgibWVkaWEiLG5jb2w9Mixucm93PTIpICsgZ3VpZGVzKGNvbG9yPSJub25lIikgKyB4bGltKDAsMTQ0MCkgKyB5bGltKC0xMDgwLDApCmBgYAoKU28gd2UnbGwgcmVtb3ZlIFJlYmVjY2EncyBtaWRhc19mb3J3YXJkIHN0b3J5LiBOZXh0LCBjaGVjayB0aGUgbWVkaWFucy4KCmBgYHtyfQppcXIgJT4lIAogIGdhdGhlcihheGlzLG1lZCx4bWVkOnltZWQpICU+JQogIGdncGxvdChhZXMoeD1tZWQsZmlsbD1heGlzKSkgKyBnZW9tX2hpc3RvZ3JhbSgpICsgZmFjZXRfZ3JpZChheGlzfi4pCgpgYGAKCkxvb2tzIGdyZWF0ISBCdXQgaXQgYWxzbyBsb29rcyBwcmV0dHkgaW50ZXJlc3RpbmcgZG9lc24ndCBpdC4uLlkgbWVkaWFuIGhhcyBhIHdpZGVyIHNwcmVhZCB0aGFuIFggbWVkaWFuLiBUaGF0IHdvdWxkIG1ha2Ugc2Vuc2UuIAoKTm93IHdlJ3JlIHJlYWR5IHRvIGRvIHN0YXRzIGJhc2VkIG9uIGdyb3VwLCBkaXJlY3Rpb24sIGV0Yy4gCgpgYGB7cn0KcmJjIDwtIHRyaWJibGUofnBhcnRpY2lwYW50LCB+bWVkaWEsICJSZWJlY2NhIiwibWlkYXNfZm9yd2FyZCIpCmlxciA8LSBpcXIgJT4lCiAgdW5ncm91cCgpICU+JQogIGFudGlfam9pbihyYmMsIGJ5PWMoInBhcnRpY2lwYW50IiwibWVkaWEiKSkgIyBmb3Igc29tZSByZWFzb24gZmlsdGVyIHdvdWxkbid0IHdvcmsKCnN1YmplY3RpbmZvIDwtIHJhd2RhdGEgJT4lCiAgc2VsZWN0KHBhcnRpY2lwYW50LG1haW5ncm91cCxncm91cCxsYW5ndWFnZSxtZWRpYSxzdG9yeSxkaXJlY3Rpb24pICU+JQogIGRpc3RpbmN0KCkgJT4lCiAgZmlsdGVyKCFpcy5uYShwYXJ0aWNpcGFudCkpCgppcXIgPC0gaXFyICU+JQogIGxlZnRfam9pbihzdWJqZWN0aW5mbyxieT1jKCJwYXJ0aWNpcGFudCIsIm1lZGlhIikpICU+JQogIGZpbHRlcighaXMubmEobWFpbmdyb3VwKSkKCmlxci5nYXRoZXIgPC0gaXFyICU+JSBnYXRoZXIoYXhpcyx2YWx1ZSx4SVFSOnltZWQpCmlxci5pcXIgPC0gZmlsdGVyKGlxci5nYXRoZXIsYXhpcz09InhJUVIiIHwgYXhpcz09InlJUVIiKQppcXIubWVkIDwtIGZpbHRlcihpcXIuZ2F0aGVyLGF4aXM9PSJ4bWVkIiB8IGF4aXM9PSJ5bWVkIikKCgpnZ3Bsb3QoaXFyLmlxcixhZXMoeD1tYWluZ3JvdXAseT12YWx1ZSxmaWxsPWRpcmVjdGlvbikpICsgCiAgZ2VvbV9ib3hwbG90KCkgKyB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoYW5nbGU9NDUsaGp1c3Q9MSkpICsKICBmYWNldF9ncmlkKC5+YXhpcykKYGBgCgpBbmQgdGhlIG1lZGlhbiB4IGFuZCB5IHBvc2l0aW9uICh0aGlzIGFzc3VtZXMgYWxsIGNhbGlicmF0aW9ucyBhcmUgY29ycmVjdCk6CgpgYGB7cn0KZ2dwbG90KGlxci5tZWQsYWVzKHg9bWFpbmdyb3VwLHk9dmFsdWUsZmlsbD1kaXJlY3Rpb24pKSArIAogIGdlb21fYm94cGxvdCgpICsgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KGFuZ2xlPTQ1LGhqdXN0PTEpKSArCiAgZmFjZXRfZ3JpZCgufmF4aXMpCmBgYAoKCkZpcnN0LCBkb2VzIHJldmVyc2FsIGhhdmUgYW4gZWZmZWN0IG9uIFggSVFSPyBXZSBoYXZlIHJhbmRvbSBpbnRlcmNlcHRzIGZvciBlYWNoIHBhcnRpY2lwYW50IGFuZCBtZWRpYSwgYW5kIGEgcmFuZG9tIHNsb3BlIGFkanVzdG1lbnQgZm9yIHJldmVyc2VkIGZvciBlYWNoIHBhcnRpY2lwYW50LiAKCmBgYHtyfQp4aXFyLnJldmVyc2FsIDwtIGxtZXIoeElRUiB+IGRpcmVjdGlvbiArIChkaXJlY3Rpb258cGFydGljaXBhbnQpICsgKDF8bWVkaWEpLCBkYXRhID0gaXFyKQpzdW1tYXJ5KHhpcXIucmV2ZXJzYWwpJGNvZWZmaWNpZW50cwpgYGAKIApXZWxwLiBOby4gWSBJUVI/CmBgYHtyfQp5aXFyLnJldmVyc2FsIDwtIGxtZXIoeUlRUiB+IGRpcmVjdGlvbiArIChkaXJlY3Rpb258cGFydGljaXBhbnQpICsgKDF8bWVkaWEpLCBkYXRhID0gaXFyKQpzdW1tYXJ5KHlpcXIucmV2ZXJzYWwpJGNvZWZmaWNpZW50cwpgYGAKCk5vIGVmZmVjdCBoZXJlIGVpdGhlci4gTGV0J3MgdHJ5IGFkZGluZyBtYWluZ3JvdXBzLiBYIElRUiBmaXJzdC4gCmBgYHtyfQp4aXFyLmdyb3VwIDwtIGxtZXIoeElRUiB+IGRpcmVjdGlvbiAqIG1haW5ncm91cCArIChkaXJlY3Rpb258cGFydGljaXBhbnQpICsgKDF8bWVkaWEpLCBkYXRhID0gaXFyKQpzdW1tYXJ5KHhpcXIuZ3JvdXApJGNvZWZmaWNpZW50cwpgYGAKClRoaXMgbWVhbnMgdGhlcmUgaXMgYSBzaWduaWZpY2FudCBkaWZmZXJlbmNlIG9mIERlYWZFYXJseSB2cy4gSGVhcmluZ0xhdGUgYW5kIEhlYXJpbmdUcmFpbmVkIG9uIHhJUVIsIGJ1dCBpbiB0aGUgZm9yd2FyZCBjb25kaXRpb24gb25seS4gQmFzaWNhbGx5LCB0aG9zZSB0d28gZ3JvdXBzIGhhdmUgYSAid2lkZXIiIHZpZXdpbmcgc3BhY2UgdGhhbiBvdGhlciBncm91cHMuCgpgYGB7cn0KeWlxci5ncm91cCA8LSBsbWVyKHlJUVIgfiBkaXJlY3Rpb24gKiBtYWluZ3JvdXAgKyAoZGlyZWN0aW9ufHBhcnRpY2lwYW50KSArICgxfG1lZGlhKSwgZGF0YSA9IGlxcikKc3VtbWFyeSh5aXFyLmdyb3VwKSRjb2VmZmljaWVudHMKYGBgCk5vIGRpZmZlcmVuY2VzIGFtb25nIGdyb3VwcyBvciByZXZlcnNhbCBlZmZlY3QgZm9yIHhJUVIuIFZpZXdpbmcgc3BhY2UgZG9lc24ndCBnZXQgc2lnbmlmaWNhbnRseSB0YWxsZXIgb3Igc2hvcnRlci4gCgojIFZpZXdpbmcgU3BhY2UgQ2hhcnRzCkkgd2FudCB0byBsZWFybiBob3cgdG8gbWFrZSByZWN0YW5nbGUgcGxvdHMgc28gaGVyZSB3ZSBnby4gVXNpbmcgZWFjaCBwYXJ0aWNpcGFudCdzIGZvdXIgeCBhbmQgeSBtZWRpYW5zIGFuZCA0IHggYW5kIHkgSVFScyAob25lIHNldCBmb3IgZWFjaCBzdG9yeSwgZm9yIDQgc3RvcmllcykuIFNvIEkgY2FuIGdldCB0aGUgbG9naWMgYW5kIGNvZGUgZG93bi4gTGV0J3MgYXNzdW1lIGFsbCBjYWxpYnJhdGlvbnMgd2VyZSBjb3JyZWN0LiBIZXJlJ3MgdGhlIGNoYXJ0IGZvciB0aGUgd2hvbGUgbWVkaWEgc2l6ZSBvZiAxNDQweDEwODAgKGFzIHJlcG9ydGVkIGluIFRvYmlpKS4gCmBgYHtyfQojIEluIHRoaXMgb3JkZXIsIHdlJ2xsIGdldCBhIGdyYW5kIG1lZGlhbiBieSB0YWtpbmcgYSBwYXJ0aWNpcGFudCdzIG1lZGlhbiBhY3Jvc3MgdGhlaXIgNCBzdG9yaWVzLCB0aGFuIHRoZSBtZWRpYW4gZm9yIGZvcndhcmQgYW5kIHJldmVyc2UgYWNyb3NzIGFsbCBwYXJ0aWNpcGFudHMuIAptZWRpYW5zIDwtIGlxciAlPiUKICBncm91cF9ieShtYWluZ3JvdXAsIHBhcnRpY2lwYW50LGRpcmVjdGlvbikgJT4lCiAgZHBseXI6OnN1bW1hcml6ZSh4SVFSID0gbWVkaWFuKHhJUVIsbmEucm09VFJVRSksCiAgICAgICAgICAgICAgICAgICB5SVFSID0gbWVkaWFuKHlJUVIsbmEucm09VFJVRSksCiAgICAgICAgICAgICAgICAgICB4bWVkID0gbWVkaWFuKHhtZWQsbmEucm09VFJVRSksCiAgICAgICAgICAgICAgICAgICB5bWVkID0gbWVkaWFuKHltZWQsbmEucm09VFJVRSkpICU+JQogIGdyb3VwX2J5KG1haW5ncm91cCwgZGlyZWN0aW9uKSAlPiUgCiAgZHBseXI6OnN1bW1hcml6ZSh4SVFSID0gbWVkaWFuKHhJUVIsbmEucm09VFJVRSksCiAgICAgICAgICAgICAgICAgICB5SVFSID0gbWVkaWFuKHlJUVIsbmEucm09VFJVRSksCiAgICAgICAgICAgICAgICAgICB4ID0gbWVkaWFuKHhtZWQsbmEucm09VFJVRSksCiAgICAgICAgICAgICAgICAgICB5ID0gbWVkaWFuKHltZWQsbmEucm09VFJVRSkpCgptZWRpYW5zIDwtIG1lZGlhbnMgJT4lCiAgbXV0YXRlKHkgPSB5Ki0xLAogICAgICAgICB4bWluID0geC0oeElRUi8yKSwKICAgICAgICAgeG1heCA9IHgrKHhJUVIvMiksCiAgICAgICAgIHltaW4gPSB5LSh5SVFSLzIpLAogICAgICAgICB5bWF4ID0geSsoeUlRUi8yKSkKCmltZyA8LSByZWFkUE5HKCJjaW5keS5wbmciKQpnIDwtIHJhc3Rlckdyb2IoaW1nLCBpbnRlcnBvbGF0ZT1UUlVFLCB3aWR0aD11bml0KDEsIm5wYyIpLCBoZWlnaHQ9dW5pdCgxLCJucGMiKSkgCgpnZ3Bsb3QobWVkaWFucywgYWVzKGZpbGw9ZGlyZWN0aW9uLGNvbG9yPWRpcmVjdGlvbikpICsKICBhbm5vdGF0aW9uX2N1c3RvbShnLCB4bWluPS1JbmYsIHhtYXg9SW5mLCB5bWluPS1JbmYsIHltYXg9SW5mKSArCiAgZ2VvbV9yZWN0KGFlcyh4bWluPXhtaW4seW1pbj15bWluLHhtYXg9eG1heCx5bWF4PXltYXgpLGFscGhhPS4xKSArIAogIHRoZW1lX2xpbmVkcmF3KCkgKyAKICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygwLDE0NDApLCBleHBhbmQgPSBjKDAsIDApKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoLTEwODAsMCksIGV4cGFuZCA9IGMoMCwgMCkpICsKICBmYWNldF93cmFwKCJtYWluZ3JvdXAiKQoKIyBnZ3Bsb3QoaXFyLmdsb2JhbCwgYWVzKGZpbGw9ZGlyZWN0aW9uLGNvbG9yPWRpcmVjdGlvbikpICsKIyAgIGFubm90YXRpb25fY3VzdG9tKGcsIHhtaW49LUluZiwgeG1heD1JbmYsIHltaW49LUluZiwgeW1heD1JbmYpICsKIyAgIGdlb21fcmVjdChhZXMoeG1pbj14bWluLHltaW49eW1pbix4bWF4PXhtYXgseW1heD15bWF4KSxhbHBoYT0uMSkgKyAKIyAgIHRoZW1lX21pbmltYWwoKSArIHhsaW0oMCwxNDQwKSArIHlsaW0oLTEwODAsMCkgKwojICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0PS0xMDgwKzg4NSkgKwojICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0PS0xMDgwKzUyNSkgKyAKIyAgIGFubm90YXRlKGdlb209InRleHQiLCB4ID0gMzAwLCB5ID0gLTEwODArNTU1LCBsYWJlbCA9ICJ1cHBlciBzaG91bGRlciBwb2ludCIpICsKIyAgIGFubm90YXRlKGdlb209InBvaW50IiwgeCA9IDUzNSwgeSA9IC0xMDgwKzUyNSkgKyAKIyAgIGFubm90YXRlKGdlb209InRleHQiLCB4ID0gNTM1LCB5ID0gLTEwODArOTEwLCBsYWJlbCA9ICJoZWlnaHQgbGluZSIpICsgCiMgICBhbm5vdGF0ZShnZW9tPSJyZWN0IiwgeG1pbiA9IDUzNSwgeG1heCA9IDUzNSszNjUsIHltaW4gPSAtNTI1LTU1MSwgeW1heCA9IC0xMDgwKzUyNSwgZmlsbD0ibWFyb29uIiwgY29sb3I9ImJsYWNrIiwgYWxwaGE9MC41KSArIAojICAgYW5ub3RhdGUoZ2VvbT0idGV4dCIsIHggPSA3MDAsIHkgPSAtOTAwLCBsYWJlbCA9ICJ0b3JzbyIpCmBgYAoKWWF5eXkhIEl0IHdvcmtlZCEgQSBiaXQgaGFyZCB0byBzZWUhIExldCdzIHpvb20gaW4uIAoKYGBge3J9CiMgZ2dwbG90KGlxci5nbG9iYWwsIGFlcyhmaWxsPWRpcmVjdGlvbixjb2xvcj1kaXJlY3Rpb24pKSArCiMgICBhbm5vdGF0aW9uX2N1c3RvbShnLCB4bWluPTAsIHhtYXg9MTQ0MCwgeW1pbj0tMTA4MCwgeW1heD0wKSArCiMgICBnZW9tX3JlY3QoYWVzKHhtaW49eG1pbix5bWluPXltaW4seG1heD14bWF4LHltYXg9eW1heCksYWxwaGE9LjEpICsgCiMgICB0aGVtZV9taW5pbWFsKCkgKyB4bGltKDYwMCw4MDApICsgeWxpbSgtNTAwLC0zMDApCgpnZ3Bsb3QobWVkaWFucywgYWVzKGZpbGw9ZGlyZWN0aW9uLGNvbG9yPWRpcmVjdGlvbikpICsKICBnZW9tX3JlY3QoYWVzKHhtaW49eG1pbix5bWluPXltaW4seG1heD14bWF4LHltYXg9eW1heCksYWxwaGE9LjEpICsgCiAgdGhlbWVfbWluaW1hbCgpICsgeGxpbSg2NzcsNzQzKSArIHlsaW0oLTQyMSwtMzcwKQoKI2dncGxvdChpcXIuZ2xvYmFsLCBhZXMoZmlsbD1kaXJlY3Rpb24sY29sb3I9ZGlyZWN0aW9uKSkgKwojICBnZW9tX3JlY3QoYWVzKHhtaW49eG1pbix5bWluPXltaW4seG1heD14bWF4LHltYXg9eW1heCksYWxwaGE9LjEpCmBgYApJIGhhdmUgdG8gZmlndXJlIG91dCBob3cgdG8gZ2V0IENpbmR5IHRvIHpvb20gaW4gLSBvciBjcm9wIGEgem9vbWVkIGluIHZlcnNpb24gb2YgQ2luZHkgbWFudWFsbHkgYW5kIHVzZSB0aGF0LgoKIyBWaWV3aW5nIFNwYWNlIENoYXJ0cyBmb3IgSW5kaXZpZHVhbHMKTm93IGxldCdzIHNlZSB0aGUgdmFyaWF0aW9uIGluIHZpZXdpbmcgc3BhY2VzIGZvciBhbGwgb3VyIGluZGl2aWR1YWxzLiBTaG91bGQgYmUgZnVuLgoKYGBge3IgZmlnLmhlaWdodD0xMCwgZmlnLndpZHRoPTI2fQppcXIuaW5kaXZpZHVhbHMgPC0gaXFyICU+JQogIHJlbmFtZSh4ID0geG1lZCwKICAgICAgICAgeSA9IHltZWQpICU+JQogIG11dGF0ZSh5ID0geSotMSwKICAgICAgICAgeG1pbiA9IHgtKHhJUVIvMiksCiAgICAgICAgIHhtYXggPSB4Kyh4SVFSLzIpLAogICAgICAgICB5bWluID0geS0oeUlRUi8yKSwKICAgICAgICAgeW1heCA9IHkrKHlJUVIvMikpCgpnZ3Bsb3QoaXFyLmluZGl2aWR1YWxzLCBhZXMoZmlsbD1kaXJlY3Rpb24sY29sb3I9ZGlyZWN0aW9uKSkgKwogIGFubm90YXRpb25fY3VzdG9tKGcsIHhtaW49LUluZiwgeG1heD1JbmYsIHltaW49LUluZiwgeW1heD1JbmYpICsKICBnZW9tX3JlY3QoYWVzKHhtaW49eG1pbix5bWluPXltaW4seG1heD14bWF4LHltYXg9eW1heCksYWxwaGE9LjEpICsgCiAgdGhlbWVfbWluaW1hbCgpICsgeGxpbSgwLDE0NDApICsgeWxpbSgtMTA4MCwwKSArIGZhY2V0X3dyYXAoImRpcmVjdGlvbiIpICsKICBnZ3RpdGxlKCJ3aXRoIElRUnMiKQpgYGAKCiMgU3RhbmRhcmQgRGV2aWF0aW9ucz8KCkxldCdzIHRyeSB1c2luZyBzdGFuZGFyZCBkZXZpYXRpb25zIGluc3RlYWQuCgpgYGB7ciBmaWcuaGVpZ2h0PTEwLCBmaWcud2lkdGg9MjZ9CnNkIDwtIHJhd2RhdGEgJT4lCiAgZ3JvdXBfYnkocGFydGljaXBhbnQsbWVkaWEpICU+JQogIGRwbHlyOjpzdW1tYXJpemUoeHNkID0gc2QoeCxuYS5ybT1UUlVFKSwKICAgICAgICAgICAgICAgICAgIHlzZCA9IHNkKHksbmEucm09VFJVRSksCiAgICAgICAgICAgICAgICAgICB4bWVhbiA9IG1lYW4oeCwgbmEucm09VFJVRSksCiAgICAgICAgICAgICAgICAgICB5bWVhbiA9IG1lYW4oeSwgbmEucm09VFJVRSkpCgpzZC5pbmRpdmlkdWFscyA8LSBzZCAlPiUKICByZW5hbWUoeCA9IHhtZWFuLAogICAgICAgICB5ID0geW1lYW4pICU+JQogIG11dGF0ZSh5ID0geSotMSwKICAgICAgICAgeG1pbiA9IHgteHNkLAogICAgICAgICB4bWF4ID0geCt4c2QsCiAgICAgICAgIHltaW4gPSB5LXlzZCwKICAgICAgICAgeW1heCA9IHkreXNkKSAlPiUKICBsZWZ0X2pvaW4oc3ViamVjdGluZm8sYnk9YygicGFydGljaXBhbnQiLCJtZWRpYSIpKSAlPiUKICBmaWx0ZXIoIWlzLm5hKG1haW5ncm91cCkpCgoKZ2dwbG90KHNkLmluZGl2aWR1YWxzLCBhZXMoZmlsbD1kaXJlY3Rpb24sY29sb3I9ZGlyZWN0aW9uKSkgKwogIGFubm90YXRpb25fY3VzdG9tKGcsIHhtaW49LUluZiwgeG1heD1JbmYsIHltaW49LUluZiwgeW1heD1JbmYpICsKICBnZW9tX3JlY3QoYWVzKHhtaW49eG1pbix5bWluPXltaW4seG1heD14bWF4LHltYXg9eW1heCksYWxwaGE9LjEpICsgCiAgdGhlbWVfbWluaW1hbCgpICsgeGxpbSgwLDE0NDApICsgeWxpbSgtMTA4MCwwKSArIGZhY2V0X3dyYXAoImRpcmVjdGlvbiIpICsKICBnZ3RpdGxlKCJ3aXRoIFNEcyIpCgoKYGBgCgpOb3cgbGV0J3MgbWFrZSBPdXRlciBMaW1pdHMgY2hhcnRzIHdoaWNoIGlzIElRUiArLy0gMiBTRHMuIApgYGB7ciBmaWcuaGVpZ2h0PTEwLCBmaWcud2lkdGg9MjZ9CnNkLmluZGl2aWR1YWxzIDwtIHNlbGVjdChzZC5pbmRpdmlkdWFscyxwYXJ0aWNpcGFudCxtZWRpYSx4c2QseXNkKQppcXJzZC5pbmRpdmlkdWFscyA8LSBsZWZ0X2pvaW4oaXFyLmluZGl2aWR1YWxzLHNkLmluZGl2aWR1YWxzLGJ5PWMoInBhcnRpY2lwYW50IiwibWVkaWEiKSkgJT4lCiAgbXV0YXRlKHhtaW4gPSB4bWluLSgyKnhzZCksCiAgICAgICAgIHhtYXggPSB4bWF4KygyKnhzZCksCiAgICAgICAgIHltaW4gPSB5bWluLSgyKnlzZCksCiAgICAgICAgIHltYXggPSB5bWF4KygyKnlzZCkpCgpnZ3Bsb3QoaXFyc2QuaW5kaXZpZHVhbHMsIGFlcyhmaWxsPWRpcmVjdGlvbixjb2xvcj1kaXJlY3Rpb24pKSArCiAgYW5ub3RhdGlvbl9jdXN0b20oZywgeG1pbj0tSW5mLCB4bWF4PUluZiwgeW1pbj0tSW5mLCB5bWF4PUluZikgKwogIGdlb21fcmVjdChhZXMoeG1pbj14bWluLHltaW49eW1pbix4bWF4PXhtYXgseW1heD15bWF4KSxhbHBoYT0uMSkgKyAKICB0aGVtZV9taW5pbWFsKCkgKyB4bGltKDAsMTQ0MCkgKyB5bGltKC0xMDgwLDApICsgZmFjZXRfd3JhcCgiZGlyZWN0aW9uIikgKwogIGdndGl0bGUoIndpdGggU0RzIikKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTEwLCBmaWcud2lkdGg9MjZ9CmlxcnNkLmluZGl2aWR1YWxzIDwtIGlxcnNkLmluZGl2aWR1YWxzICU+JQogIGdyb3VwX2J5KGRpcmVjdGlvbikgJT4lCiAgZHBseXI6OnN1bW1hcml6ZSh4ID0gbWVhbih4LG5hLnJtPVRSVUUpLAogICAgICAgICAgICB5ID0gbWVhbih5LG5hLnJtPVRSVUUpLAogICAgICAgICAgICB4bWluID0gbWVhbih4bWluLG5hLnJtPVRSVUUpLAogICAgICAgICAgICB5bWluID0gbWVhbih5bWluLG5hLnJtPVRSVUUpLAogICAgICAgICAgICB4bWF4ID0gbWVhbih4bWF4LG5hLnJtPVRSVUUpLAogICAgICAgICAgICB5bWF4ID0gbWVhbih5bWF4LG5hLnJtPVRSVUUpKQpnZ3Bsb3QoaXFyc2QuaW5kaXZpZHVhbHMsIGFlcyhmaWxsPWRpcmVjdGlvbixjb2xvcj1kaXJlY3Rpb24pKSArCiAgYW5ub3RhdGlvbl9jdXN0b20oZywgeG1pbj0tSW5mLCB4bWF4PUluZiwgeW1pbj0tSW5mLCB5bWF4PUluZikgKwogIGdlb21fcmVjdChhZXMoeG1pbj14bWluLHltaW49eW1pbix4bWF4PXhtYXgseW1heD15bWF4KSxhbHBoYT0uMSkgKyAKICB0aGVtZV9taW5pbWFsKCkgKyB4bGltKDAsMTQ0MCkgKyB5bGltKC0xMDgwLDApICsgZmFjZXRfd3JhcCgiZGlyZWN0aW9uIikgKwogIGdndGl0bGUoIkF2ZXJhZ2Ugb2YgYWJvdmUgY2hhcnQgKHJhaW4ncyBvdXRlciBsaW1pdHMpIikKCmBgYAoKIyBYWSBTcGFjZSBEYXRhIC0gTXVsdGlwbGUgUGxvdHMKCkZpcnN0IGxldCdzIHByZXAgdGhlIGRhdGEuIApgYGB7cn0KbXVsdGlwbGVzIDwtIHJhd2RhdGEgJT4lCiAgZmlsdGVyKCFpcy5uYSh4KSkgJT4lCiAgZmlsdGVyKCFpcy5uYSh5KSkgJT4lCiAgcmVuYW1lKGxhbmcgPSBtYWluZ3JvdXAsCiAgICAgICAgIG5hbWUgPSBwYXJ0aWNpcGFudCkgJT4lCiAgZ3JvdXBfYnkobmFtZSwgbGFuZywgZGlyZWN0aW9uLCBzdG9yeSkgJT4lCiAgc3VtbWFyaXNlKHhJUVIgPSBJUVIoeCxuYS5ybT1UUlVFKSwKICAgICAgICAgICAgeUlRUiA9IElRUih5LG5hLnJtPVRSVUUpLAogICAgICAgICAgICB4bWVkID0gbWVkaWFuKHgsIG5hLnJtPVRSVUUpLAogICAgICAgICAgICB5bWVkID0gbWVkaWFuKHksIG5hLnJtPVRSVUUpLAogICAgICAgICAgICBhcmVhID0geElRUip5SVFSLAogICAgICAgICAgICB4XzkwID0gcXVhbnRpbGUoeCwgLjk1LCBuYS5ybT1UUlVFKSAtIHF1YW50aWxlKHgsIC4wNSwgbmEucm09VFJVRSksCiAgICAgICAgICAgIHlfOTAgPSBxdWFudGlsZSh5LCAuOTUsIG5hLnJtPVRSVUUpIC0gcXVhbnRpbGUoeSwgLjA1LCBuYS5ybT1UUlVFKSwKICAgICAgICAgICAgYXJlYV85MCA9ICh4XzkwKSAqICh5XzkwKSwKICAgICAgICAgICAgeF9tZWFuID0gbWVhbih4LCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICB5X21lYW4gPSBtZWFuKHksIG5hLnJtID0gVFJVRSksCiAgICAgICAgICAgIHhfc2QgPSBzZCh4LCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICB5X3NkID0gc2QoeSwgbmEucm0gPSBUUlVFKSwKICAgICAgICAgICAgeF8xc2QgPSAoeF9tZWFuK3hfc2QpIC0gKHhfbWVhbi14X3NkKSwKICAgICAgICAgICAgeV8xc2QgPSAoeV9tZWFuK3lfc2QpIC0gKHlfbWVhbi15X3NkKSwKICAgICAgICAgICAgYXJlYV8xc2QgPSB4XzFzZCAqIHlfMXNkLAogICAgICAgICAgICB4XzJzZCA9ICh4X21lYW4rKHhfc2QqMikpIC0gKHhfbWVhbi0oeF9zZCoyKSksCiAgICAgICAgICAgIHlfMnNkID0gKHlfbWVhbisoeV9zZCoyKSkgLSAoeV9tZWFuLSh5X3NkKjIpKSwKICAgICAgICAgICAgYXJlYV8yc2QgPSB4XzJzZCAqIHlfMnNkKSAlPiUKICBncm91cF9ieShuYW1lLCBsYW5nLCBkaXJlY3Rpb24pICU+JQogIHN1bW1hcmlzZV9pZihpcy5kb3VibGUsIGZ1bnMobWVhbiksIG5hLnJtID0gVCkgJT4lCiAgZ3JvdXBfYnkobGFuZywgZGlyZWN0aW9uKSAlPiUKICBzdW1tYXJpc2VfaWYoaXMuZG91YmxlLCBmdW5zKG1lYW4pLCBuYS5ybSA9IFQpICU+JQogIGZpbHRlcihsYW5nID09ICJEZWFmRWFybHkiIHx8IGxhbmcgPT0gIkhlYXJpbmdOb3ZpY2UiKQoKaW1nIDwtIHBuZzo6cmVhZFBORygiY2luZHkucG5nIikKZyA8LSBncmlkOjpyYXN0ZXJHcm9iKGltZywgaW50ZXJwb2xhdGU9VFJVRSwgd2lkdGg9dW5pdCgxLCJucGMiKSwgaGVpZ2h0PXVuaXQoMSwibnBjIikpIAoKYGBgCgojIyBJUVIgKE1pZGRsZSA1MCUpCkxldCdzIHNlZS4gCmBgYHtyfQpjdXJyX2RhdGEgPC0gbXVsdGlwbGVzICU+JSAKICB1bmdyb3VwKCkgJT4lCiAgc2VsZWN0KGxhbmcsIGRpcmVjdGlvbiwgeG1lZCwgeW1lZCwgeElRUiwgeUlRUikgJT4lCiAgZ3JvdXBfYnkobGFuZywgZGlyZWN0aW9uKSAlPiUKICBzdW1tYXJpc2UoeG1pbiA9IHhtZWQtKHhJUVIvMiksCiAgICAgICAgIHhtYXggPSB4bWVkKyh4SVFSLzIpLAogICAgICAgICB5bWluID0gLTEqKHltZWQtKHlJUVIvMikpLAogICAgICAgICB5bWF4ID0gLTEqKHltZWQrKHlJUVIvMikpKQoKZ2dwbG90KGN1cnJfZGF0YSwgYWVzKGZpbGw9ZGlyZWN0aW9uLGNvbG9yPWRpcmVjdGlvbikpICsKICBhbm5vdGF0aW9uX2N1c3RvbShnLCB4bWluPS1JbmYsIHhtYXg9SW5mLCB5bWluPS1JbmYsIHltYXg9SW5mKSArCiAgZ2VvbV9yZWN0KGFlcyh4bWluPXhtaW4seW1pbj15bWluLHhtYXg9eG1heCx5bWF4PXltYXgpLGFscGhhPS4xKSArIAogIHRoZW1lX2xpbmVkcmF3KCkgKwogIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKDAsMTQ0MCksIGV4cGFuZCA9IGMoMCwgMCkpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygtMTA4MCwwKSwgZXhwYW5kID0gYygwLCAwKSkgKwogIGZhY2V0X3dyYXAoImxhbmciKQpgYGAKCiMjIE1pZGRsZSA5MCUKU28gSSBjYWxjdWxhdGVkIHRoZSBhdmVyYWdlIG1lZGlhbiBhY3Jvc3MsIGFuZCB0aGUgbWlkZGxlIDkwJSBvZiB0aGUgZGF0YS4gCmBgYHtyfQpjdXJyX2RhdGEgPC0gbXVsdGlwbGVzICU+JSAKICB1bmdyb3VwKCkgJT4lCiAgc2VsZWN0KGxhbmcsIGRpcmVjdGlvbiwgeG1lZCwgeW1lZCwgeF85MCwgeV85MCkgJT4lCiAgZ3JvdXBfYnkobGFuZywgZGlyZWN0aW9uKSAlPiUKICBzdW1tYXJpc2UoeG1pbiA9IHhtZWQtKHhfOTAvMiksCiAgICAgICAgIHhtYXggPSB4bWVkKyh4XzkwLzIpLAogICAgICAgICB5bWluID0gLTEqKHltZWQtKHlfOTAvMikpLAogICAgICAgICB5bWF4ID0gLTEqKHltZWQrKHlfOTAvMikpKQoKZ2dwbG90KGN1cnJfZGF0YSwgYWVzKGZpbGw9ZGlyZWN0aW9uLGNvbG9yPWRpcmVjdGlvbikpICsKICBhbm5vdGF0aW9uX2N1c3RvbShnLCB4bWluPS1JbmYsIHhtYXg9SW5mLCB5bWluPS1JbmYsIHltYXg9SW5mKSArCiAgZ2VvbV9yZWN0KGFlcyh4bWluPXhtaW4seW1pbj15bWluLHhtYXg9eG1heCx5bWF4PXltYXgpLGFscGhhPS4xKSArIAogIHRoZW1lX2xpbmVkcmF3KCkgKwogIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKDAsMTQ0MCksIGV4cGFuZCA9IGMoMCwgMCkpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygtMTA4MCwwKSwgZXhwYW5kID0gYygwLCAwKSkgKwogIGZhY2V0X3dyYXAoImxhbmciKQpgYGAKCgojIyDCsTEgU0QgKE1pZGRsZSA2OCUpClNvIHRoaXMgaXMgdXNpbmcgdGhlIG1lYW4gb2YgdGhlIG1lYW5zLCBwbHVzIG9yIG1pbnVzIG9uZSBTRC4gIFRoaXMgaXMgZXF1aXZhbGVudCB0byBtaWRkbGUgNjglLiAKYGBge3J9CmN1cnJfZGF0YSA8LSBtdWx0aXBsZXMgJT4lIAogIHVuZ3JvdXAoKSAlPiUKICBzZWxlY3QobGFuZywgZGlyZWN0aW9uLCB4X21lYW4sIHlfbWVhbiwgeF8xc2QsIHlfMXNkKSAlPiUKICBncm91cF9ieShsYW5nLCBkaXJlY3Rpb24pICU+JQogIHN1bW1hcmlzZSh4bWluID0geF9tZWFuLSh4XzFzZC8yKSwKICAgICAgICAgeG1heCA9IHhfbWVhbisoeF8xc2QvMiksCiAgICAgICAgIHltaW4gPSAtMSooeV9tZWFuLSh5XzFzZC8yKSksCiAgICAgICAgIHltYXggPSAtMSooeV9tZWFuKyh5XzFzZC8yKSkpCgpnZ3Bsb3QoY3Vycl9kYXRhLCBhZXMoZmlsbD1kaXJlY3Rpb24sY29sb3I9ZGlyZWN0aW9uKSkgKwogIGFubm90YXRpb25fY3VzdG9tKGcsIHhtaW49LUluZiwgeG1heD1JbmYsIHltaW49LUluZiwgeW1heD1JbmYpICsKICBnZW9tX3JlY3QoYWVzKHhtaW49eG1pbix5bWluPXltaW4seG1heD14bWF4LHltYXg9eW1heCksYWxwaGE9LjEpICsgCiAgdGhlbWVfbGluZWRyYXcoKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cyA9IGMoMCwxNDQwKSwgZXhwYW5kID0gYygwLCAwKSkgKwogIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKC0xMDgwLDApLCBleHBhbmQgPSBjKDAsIDApKSArCiAgZmFjZXRfd3JhcCgibGFuZyIpCmBgYAoKIyMgwrEyIFNEIChNaWRkbGUgOTYlKQpBbmQgdGhpcyBpcyB1c2luZyB0aGUgbWVhbiBvZiB0aGUgbWVhbnMsIHBsdXMgb3IgbWludXMgdHdvIFNELiAgVGhpcyBpcyBlcXVpdmFsZW50IHRvIG1pZGRsZSA5NiUuIApgYGB7cn0KY3Vycl9kYXRhIDwtIG11bHRpcGxlcyAlPiUgCiAgdW5ncm91cCgpICU+JQogIHNlbGVjdChsYW5nLCBkaXJlY3Rpb24sIHhfbWVhbiwgeV9tZWFuLCB4XzJzZCwgeV8yc2QpICU+JQogIGdyb3VwX2J5KGxhbmcsIGRpcmVjdGlvbikgJT4lCiAgc3VtbWFyaXNlKHhtaW4gPSB4X21lYW4tKHhfMnNkLzIpLAogICAgICAgICB4bWF4ID0geF9tZWFuKyh4XzJzZC8yKSwKICAgICAgICAgeW1pbiA9IC0xKih5X21lYW4tKHlfMnNkLzIpKSwKICAgICAgICAgeW1heCA9IC0xKih5X21lYW4rKHlfMnNkLzIpKSkKCmdncGxvdChjdXJyX2RhdGEsIGFlcyhmaWxsPWRpcmVjdGlvbixjb2xvcj1kaXJlY3Rpb24pKSArCiAgYW5ub3RhdGlvbl9jdXN0b20oZywgeG1pbj0tSW5mLCB4bWF4PUluZiwgeW1pbj0tSW5mLCB5bWF4PUluZikgKwogIGdlb21fcmVjdChhZXMoeG1pbj14bWluLHltaW49eW1pbix4bWF4PXhtYXgseW1heD15bWF4KSxhbHBoYT0uMSkgKyAKICB0aGVtZV9saW5lZHJhdygpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygwLDE0NDApLCBleHBhbmQgPSBjKDAsIDApKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoLTEwODAsMCksIGV4cGFuZCA9IGMoMCwgMCkpICsKICBmYWNldF93cmFwKCJsYW5nIikKYGBgCg==